package xuanmu.office.excel.data.generator.generator;

import jakarta.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import xuanmu.office.excel.data.generator.config.BaseConfig;
import xuanmu.office.excel.data.generator.dao.RouteDao;
import xuanmu.office.excel.data.generator.dao.TruckDao;
import xuanmu.office.excel.data.generator.entity.Route;
import xuanmu.office.excel.data.generator.entity.RowData;
import xuanmu.office.excel.data.generator.entity.Truck;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * RowDataGenerator 类用于生成行数据，主要用于模拟生成与运输相关的行数据。
 * 该类通过依赖注入的方式获取车辆信息，并根据预定义的货物类型、线路和距离范围随机生成运输记录。
 * 生成的数据包括车牌号、车辆类型、额定载重量、日期、货物类型、线路、单次里程、运输趟次、总公里数、货运量和周转量等信息。
 *
 * <p>主要功能：
 * <ul>
 *     <li>初始化货物类型、线路及距离范围</li>
 *     <li>从数据库读取车辆信息</li>
 *     <li>根据给定的年、月、日生成随机的运输记录</li>
 * </ul>
 */
@Component
public class RowDataGenerator {

    @Autowired
    private TruckDao truckDao;
    @Autowired
    private RouteDao routeDao;

    // 货物类型
    private List<String> cargoTypes;
    // 路线列表
    private List<Route> routeList;
    // 车辆列表
    private List<Truck> truckList;

    // 日期格式化工具
    private SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");

    @PostConstruct
    public void init() throws Exception {
        // 初始化货品类型的列表
        this.cargoTypes = Arrays.asList(BaseConfig.CARGO_TYPE_ARRAY);
        // 读取路线的列表
        this.routeList = routeDao.list();
        // 读取车辆信息列表
        this.truckList = truckDao.list();
    }

    /**
     * 生成整月的所有数据
     *
     * @param year                年
     * @param month               月
     * @param dayOfMonth          截止日
     * @param totalTurnoverVolume 总周转量（所有车辆的总周转量）
     * @return 多条数据
     */
    public List<RowData> generateRowDataList(int year, int month, int dayOfMonth, int totalTurnoverVolume) {
        // 将要生成的数据
        List<RowData> rowDataList = new ArrayList<>();
        // 计算所有车辆的载重量
        double totalRatedLoadCapacity = 0;
        for (Truck truck : truckList) {
            totalRatedLoadCapacity += truck.getRatedLoadCapacity();
        }
        // 计算每单位载重量对应的周转量
        int turnoverVolumePerRatedLoadCapacity = totalTurnoverVolume / (int) totalRatedLoadCapacity;
        // 生成每车的数据
        for (Truck truck : truckList) {
            // 计算当前车的周转量
            int maxTurnoverVolume = (int) (turnoverVolumePerRatedLoadCapacity * truck.getRatedLoadCapacity());
            // 生成每辆车的数据
            List<RowData> singleTruckRowDataList = generateSingleTruckRowDataList(year, month, dayOfMonth, truck, maxTurnoverVolume);
            // 保存到最终的结果中
            rowDataList.addAll(singleTruckRowDataList);
        }
        return rowDataList;
    }

    /**
     * 生成单台货车整月的数据
     *
     * @param year              年
     * @param month             月
     * @param dayOfMonth        截止日
     * @param truck             货车信息
     * @param maxTurnoverVolume 整月最大周转量
     * @return 多条数据
     */
    private List<RowData> generateSingleTruckRowDataList(int year, int month, int dayOfMonth, Truck truck, int maxTurnoverVolume) {
        System.out.println("准备生成车辆【" + truck + "】的数据，可用周转数：" + maxTurnoverVolume);
        // 将要生成的数据
        List<RowData> rowDataList = new ArrayList<>();

        // 随机对象
        Random random = new Random();

        // 上次终点
        String lastDestination = null;
        // 当前天已经行驶里程
        int currentDayDistance = 0;
        // 当前月已经行驶里程
        int currentMonthDistance = 0;
        // 当前已经累计的周转量
        int currentTurnoverVolume = 0;

        // 设置日期为1号
        Calendar calendar = new GregorianCalendar(year, month - 1, 1);
        // 当月最大天数
        int maxDays = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);

        // 根据天数循环，准备生成数据
        for (int i = 1; i <= maxDays; i++) {
            // 确定当天日期
            calendar.set(Calendar.DAY_OF_MONTH, i);
            System.out.println("\t日期：" + dateFormat.format(calendar.getTime()));

            // 如果当月已经行驶里程已达上限则跳出循环
            if (currentMonthDistance >= BaseConfig.MAX_DISTANCE_PER_MONTH) {
                System.out.println("\t当月累计里程已达上限，结束");
                break;
            }
            // 如果当月累计的周转量已达上限则跳出循环
            if (currentTurnoverVolume >= maxTurnoverVolume) {
                System.out.println("\t累计周转量已达上限，结束");
                break;
            }

            // 每天有3成概率不生成数据
            if (random.nextInt(10) < 3) {
                System.out.println("\t\t随机休息，当天不生成数据");
                continue;
            }

            // 清零当天已经行驶的里程数
            currentDayDistance = 0;

            // 每天可能生成多条数据
            while (currentDayDistance < BaseConfig.MAX_DISTANCE_PER_DAY) {
                // 获取可用的路线
                Route route = getRoute(lastDestination, currentDayDistance);
                System.out.println("\t\t可用线路：" + route);
                // 如果无法获取路线，则当天结束
                if (route == null) {
                    System.out.println("\t\t无法获取可用线路，当天结束");
                    break;
                }

                // 生成数据
                RowData rowData = generateSingleRowData(calendar, truck, route);
                // 保存本次生成的数据
                rowDataList.add(rowData);

                // 更新本次终点
                lastDestination = rowData.getDestination();
                // 更新当日已经行驶的里程数
                currentDayDistance += rowData.getTotalTripDistance();
                // 更新当月已经行驶的里程数
                currentMonthDistance += rowData.getTotalTripDistance();
                // 更新当前已经累计的周转量
                currentTurnoverVolume += rowData.getTurnoverVolume();
            }
        }

        // 统计，仅用于输出，无其它功能
        int totalTurnoverVolume = 0;
        for (RowData rowData : rowDataList) {
            totalTurnoverVolume += rowData.getTurnoverVolume();
        }
        System.out.println("【" + truck.getLicensePlate() + "】本月共有" + rowDataList.size() +
                "条数据，分配得到的周转量为：" + maxTurnoverVolume + "，实际总周转量为：" + totalTurnoverVolume);

        return rowDataList;
    }

    /**
     * 生成单条数据
     *
     * @param calendar 日期
     * @param truck    货车
     * @param route    路线
     * @return 单条数据
     */
    private RowData generateSingleRowData(Calendar calendar, Truck truck, Route route) {
        // 随机对象
        Random random = new Random();

        // 日期
        String dateString = dateFormat.format(calendar.getTime());

        // 随机货物类型
        String cargoType = cargoTypes.get(random.nextInt(cargoTypes.size()));

        // 随机单次里程
        int distance = random.nextInt(route.getMaxDistance() - route.getMinDistance()) + route.getMinDistance();

        // 随机运输总趟次：固定为1
        int tripCount = 1; // random.nextInt(2) + 1;

        // 本次货运量
        double cargoVolume = Math.round(truck.getRatedLoadCapacity() * tripCount * 100.0) / 100.0;

        // 总公里数
        int totalTripDistance = tripCount * distance;

        // 周转量
        double turnoverVolume = Math.round(cargoVolume * distance * 100.0) / 100.0;

        RowData rowData = new RowData();
        rowData.setDate(dateString);
        rowData.setLicensePlate(truck.getLicensePlate());
        rowData.setStructureType(truck.getStructureType());
        rowData.setRatedLoadCapacity(truck.getRatedLoadCapacity());

        rowData.setDeparture(route.getDeparture());
        rowData.setDestination(route.getDestination());

        rowData.setCargoType(cargoType);

        rowData.setRatedLoadCapacityCopy(truck.getRatedLoadCapacity());

        rowData.setTripCount(tripCount);
        rowData.setCargoVolume(cargoVolume);

        rowData.setDistance(distance);
        rowData.setTotalTripDistance(totalTripDistance);
        rowData.setTurnoverVolume(turnoverVolume);

        return rowData;
    }

    /**
     * 获取路线
     *
     * @param departure          要求的起点
     * @param currentDayDistance 当天已经行驶里程
     * @return 路线，如果无可用路线，则返回null
     */
    private Route getRoute(String departure, int currentDayDistance) {
        // 备份路线集合
        List<Route> routeList = new ArrayList<>(this.routeList);
        System.out.println("\t\t开始查找可用线路……");
        // 如果指定了起点，则移除不符合的路线
        if (departure != null) {
            Iterator<Route> iterator = routeList.iterator();
            while (iterator.hasNext()) {
                Route route = iterator.next();
                if (!route.getDeparture().equals(departure)) {
                    iterator.remove();
                }
            }
        }
        // 如果没有可用的路线，则返回null
        if (routeList.size() == 0) {
            System.out.println("\t\t没有起点符合的路线");
            return null;
        }
        // 根据当天剩余可行驶里程，获取可用的路线
        int remainDistance = BaseConfig.MAX_DISTANCE_PER_DAY - currentDayDistance;
        Iterator<Route> iterator = routeList.iterator();
        while (iterator.hasNext()) {
            Route route = iterator.next();
            if (route.getMaxDistance() > remainDistance) {
                iterator.remove();
            }
        }
        // 如果没有可用的路线，则返回null
        if (routeList.size() == 0) {
            System.out.println("\t\t没有当天剩余里程可以到达的路线");
            return null;
        }
        // 返回一个随机的路线
        Random random = new Random();
        return routeList.get(random.nextInt(routeList.size()));
    }

}
